package three_shang.智能算法.AlgorithmCompare;

/**
 * @program: PSO
 * @description:
 * @author: DongGuoFeiFei
 * @create: 2024-10-22
 **/

import java.util.Arrays;
import java.util.Random;

public class GeneticAlgorithm {
    static final int POPULATION_SIZE = 30;
    static final int MAX_GENERATIONS = 10000;
    static final double CROSSOVER_PROB = 0.9;
    static final double MUTATION_PROB = 0.01;
    static final double MIN_X = -10;
    static final double MAX_X = 10;
    static final int NUM_VARS = 8;
    static Random rand = new Random();

    public static double evaluate(double[] x) {
        double denominator = Math.abs(x[0] + 1) + Math.abs(x[1]) + Math.abs(x[2] - 1) + Math.abs(x[3] - 2)
                + Math.abs(x[4] + 2) + Math.abs(x[5] - 3) + Math.abs(x[6] + 3) + 1;
        return 1.0 / denominator;
    }

    public static double[] randomSolution() {
        double[] solution = new double[NUM_VARS];
        for (int i = 0; i < NUM_VARS; i++) {
            solution[i] = MIN_X + (MAX_X - MIN_X) * rand.nextDouble();
        }
        return solution;
    }

    public static double[] selectParent(double[][] population, double[] fitness) {
        int tournamentSize = 3;
        double[] best = null;
        double bestFitness = Double.NEGATIVE_INFINITY;

        for (int i = 0; i < tournamentSize; i++) {
            int index = rand.nextInt(POPULATION_SIZE);
            if (fitness[index] > bestFitness) {
                best = population[index];
                bestFitness = fitness[index];
            }
        }
        return best.clone();
    }

    //交配
    public static void crossover(double[] parent1, double[] parent2) {
        if (rand.nextDouble() < CROSSOVER_PROB) {
            int crossoverPoint = rand.nextInt(NUM_VARS);
            for (int i = crossoverPoint; i < NUM_VARS; i++) {
                double temp = parent1[i];
                parent1[i] = parent2[i];
                parent2[i] = temp;
            }
        }
    }

    public static void mutate(double[] solution) {
        for (int i = 0; i < NUM_VARS; i++) {
            if (rand.nextDouble() < MUTATION_PROB) {
                solution[i] += (rand.nextDouble() - 0.5);
                solution[i] = Math.max(MIN_X, Math.min(MAX_X, solution[i]));
            }
        }
    }

    public static void printBestSolution(int generation, double[][] population, double[] fitness) {
        double bestFitness = Arrays.stream(fitness).max().orElse(0);
        int bestIndex = -1;
        for (int i = 0; i < POPULATION_SIZE; i++) {
            if (fitness[i] == bestFitness) {
                bestIndex = i;
                break;
            }
        }

        System.out.println("次数:    " + generation + ", 最佳适应值: " + bestFitness);
    }

    public static void main(String[] args) {
        // Initialize population
        double[][] population = new double[POPULATION_SIZE][NUM_VARS];
        double[] fitness = new double[POPULATION_SIZE];

        for (int i = 0; i < POPULATION_SIZE; i++) {
            population[i] = randomSolution();
            fitness[i] = evaluate(population[i]);
        }

        int generation = 0;
        while (generation <= MAX_GENERATIONS) {
            double[][] newPopulation = new double[POPULATION_SIZE][NUM_VARS];

            for (int i = 0; i < POPULATION_SIZE; i += 2) {
                // Selection
                double[] parent1 = selectParent(population, fitness);
                double[] parent2 = selectParent(population, fitness);

                crossover(parent1, parent2);

                mutate(parent1);
                mutate(parent2);

                newPopulation[i] = parent1;
                newPopulation[i + 1] = parent2;
            }

            for (int i = 0; i < POPULATION_SIZE; i++) {
                fitness[i] = evaluate(newPopulation[i]);
            }

            population = newPopulation;

            if (generation % 500 == 0) {
                printBestSolution(generation, population, fitness);
            }

            generation++;
        }
    }
}
